package com.uum.admin.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.uum.admin.pojo.entity.*;
import com.uum.admin.mapper.SysMenuMapper;
import com.uum.admin.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.uum.web.util.JwtUtils;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

    private final SysMenuRoleService sysMenuRoleService;
    private final SysRoleService sysRoleService;

    /**
     * 根据用户的角色ID查询相应的菜单列表
     *
     * @param roleIds
     * @return
     */
    @Override
    public List<SysMenu> listMenuByUserRoleId(List<Long> roleIds) {
        return listMenu(roleIds);
    }

    @Override
    public List<SysMenu> listMenu() {
        return listMenu(null);
    }

    /**
     * 可根据角色ID查询出所有菜单（包括按钮）并组装成树形结构
     *
     * @param roleIds 角色ID集合
     * @return
     */
    public List<SysMenu> listMenu(List<Long> roleIds) {
        //判断是否超级管理员
        List<SysMenu> menus = new ArrayList<>();
        if (JwtUtils.isAdministrator()) {
            menus = baseMapper.selectList(new QueryWrapper<SysMenu>().orderByAsc("order_num"));
        } else {
            //空的
            if (CollUtil.isEmpty(roleIds)) {
                roleIds = sysRoleService.getRoleIds();
            }
            //根据角色ID获取该角色所拥有的菜单ID
            List<Long> menuIdList = sysMenuRoleService.list(
                    new LambdaQueryWrapper<SysMenuRole>().
                            in(SysMenuRole::getRoleId, roleIds)
                            .select(SysMenuRole::getMenuId)
                            .groupBy(SysMenuRole::getMenuId)
            ).stream().map(SysMenuRole::getMenuId).collect(Collectors.toList());
            if (!menuIdList.isEmpty()) {
                //根据菜单ID查询出菜单
                menus = baseMapper.selectList(new LambdaQueryWrapper<SysMenu>().in(SysMenu::getMenuId, menuIdList).orderByAsc(SysMenu::getOrderNum));
            }
        }
        return convertListToTree(menus);
    }

    /**
     * 组装成树形结构
     *
     * @param menusList 菜单集合
     * @return
     */
    private List<SysMenu> convertListToTree(List<SysMenu> menusList) {
        if (CollUtil.isEmpty(menusList)) {
            return null;
        }
        List<SysMenu> collect = menusList.stream()
                .filter(m -> m.getParentId() == 0)
                .map(m -> m.setChildren(setMenuChildren(m, menusList)))
                .collect(Collectors.toList());
        return collect;
    }

    /**
     * 递归查找所有子菜单
     *
     * @param current 当前菜单
     * @param all     所有菜单
     * @return
     */
    private List<SysMenu> setMenuChildren(SysMenu current, List<SysMenu> all) {
        List<SysMenu> childrenList = all.stream()
                .filter(m -> m.getParentId().equals(current.getMenuId()))
                .map(m -> {
                    m.setParentName(current.getName());
                    m.setChildren(setMenuChildren(m, all));
                    return m;
                })
                .collect(Collectors.toList());
        return childrenList;
    }


    /**
     * 根据条件查询出菜单树
     *
     * @param name
     * @return
     */
    @Override
    public List<SysMenu> listMenuByName(String name) {
        List<SysMenu> menuTree = listMenu(null);
        if (StrUtil.isNotBlank(name)) {
            return filterTree(name, menuTree);
        }
        return menuTree;
    }


    /**
     * 根据名字过滤菜单树
     *
     * @param name     菜单名字
     * @param menuTree 菜单树
     * @return
     */
    private List<SysMenu> filterTree(String name, List<SysMenu> menuTree) {
        List<SysMenu> filterNameList = new ArrayList<>(menuTree.size());
        //查询该名字的节点ID
        List<SysMenu> menuIdList = baseMapper.selectList(new QueryWrapper<SysMenu>().like("name", name).select("menu_id"));
        if (menuIdList.isEmpty()) {
            return null;
        }
        List<Long> idList = menuIdList.stream().map(item -> item.getMenuId()).collect(Collectors.toList());
        for (SysMenu sysMenu : menuTree) {
            SysMenu menu = filterTree(sysMenu, idList);
            filterNameList.add(menu);
        }
        //移除空集合
        filterNameList.removeIf(Objects::isNull);
        return filterNameList;
    }

    private SysMenu filterTree(SysMenu tree, List<Long> idList) {
        if (isRemoveNode(tree, idList)) {
            return null;
        }
        Iterator<SysMenu> iterator = tree.getChildren().iterator();
        while (iterator.hasNext()) {
            SysMenu child = iterator.next();
            deleteNode(child, iterator, idList);
        }
        return tree;
    }

    /**
     * 判断该节点是否该删除
     *
     * @param root   原数据（根）
     * @param idList 命中的节点
     * @return true需要删除 false不能被删除
     */
    private boolean isRemoveNode(SysMenu root, List<Long> idList) {
        List<SysMenu> children = root.getChildren();
        //叶子节点
        if (CollectionUtils.isEmpty(children)) {
            return !idList.contains(root.getMenuId());
        }
        //子节点
        if (idList.contains(root.getMenuId())) {
            return false;
        }
        //如果存在在一个子节点不能删除，那么就不删除
        boolean bool = true;
        for (SysMenu child : children) {
            if (!isRemoveNode(child, idList)) {
                bool = false;
                break;
            }
        }
        return bool;
    }


    /**
     * 删除节点
     *
     * @param child
     * @param iterator
     * @param idList
     */
    private void deleteNode(SysMenu child, Iterator<SysMenu> iterator, List<Long> idList) {
        if (isRemoveNode(child, idList)) {
            iterator.remove();
            return;
        }

        List<SysMenu> childrenList = child.getChildren();
        if (CollectionUtils.isEmpty(childrenList)) {
            return;
        }
        Iterator<SysMenu> children = childrenList.iterator();
        while (children.hasNext()) {
            SysMenu childChild = children.next();
            deleteNode(childChild, children, idList);
        }
    }


    @Override
    public boolean delMenuTreeById(Long id) {
        // 通过id找到它所有的子菜单的cid
        // 将找到的cid 放进一个集合中 用于批量删除
        List<Long> delIdsList = new ArrayList<>();
        delIdsList.add(id);
        //递归查询出所有子菜单的id
        findChildrenMenuId(id, delIdsList);
        int effectCount = baseMapper.deleteBatchIds(delIdsList);
        return effectCount > 0 ? true : false;
    }


    /**
     * 递归查询出指定id下的所有子菜单的ID
     *
     * @param id         指定的id
     * @param delIdsList 用户存放的子菜单ID的集合
     */
    private void findChildrenMenuId(Long id, List delIdsList) {
        List<SysMenu> childrenList = baseMapper.selectList(new QueryWrapper<SysMenu>().eq("parent_id", id).select("menu_id"));
        if (childrenList.isEmpty()) {
            return;
        }
        childrenList.stream().forEach(item -> {
            delIdsList.add(item.getMenuId());
            findChildrenMenuId(item.getMenuId(), delIdsList);
        });
    }
}
